package indigo.mybatis.dao.criterion;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

public abstract class Criterion implements Serializable {
	private static final long serialVersionUID = -8875765345596944249L;

	private static final Criterion NOTHING = new Junction(Junction.Logical.AND);

	public abstract List<FlattenPart> flatten();

	public static Criterion ids(Object... ids) {
		return new Identifier(ids);
	}

	public static Criterion ids(Collection<?> ids) {
		return new Identifier(ids);
	}

	public static Criterion eq(String property, Object operand) {
		return new Condition(property, Condition.Operator.EQ, operand);
	}

	public static Criterion eqIgnoreCase(String property, String operand) {
		return new Condition(property, Condition.Operator.EQ_CI, operand);
	}

	public static Criterion ne(String property, Object operand) {
		return new Condition(property, Condition.Operator.NE, operand);
	}

	public static Criterion neIgnoreCase(String property, String operand) {
		return new Condition(property, Condition.Operator.NE_CI, operand);
	}

	public static Criterion gt(String property, Object operand) {
		return new Condition(property, Condition.Operator.GT, operand);
	}

	public static Criterion ge(String property, Object operand) {
		return new Condition(property, Condition.Operator.GE, operand);
	}

	public static Criterion lt(String property, Object operand) {
		return new Condition(property, Condition.Operator.LT, operand);
	}

	public static Criterion le(String property, Object operand) {
		return new Condition(property, Condition.Operator.LE, operand);
	}

	public static Criterion isNull(String property) {
		return new Condition(property, Condition.Operator.IS_NULL);
	}

	public static Criterion isNotNull(String property) {
		return new Condition(property, Condition.Operator.IS_NOT_NULL);
	}

	public static Criterion like(String property, String operand) {
		return new Condition(property, Condition.Operator.LIKE, operand);
	}

	public static Criterion likeIgnoreCase(String property, String operand) {
		return new Condition(property, Condition.Operator.LIKE_CI, operand);
	}

	public static Criterion notLike(String property, String operand) {
		return new Condition(property, Condition.Operator.NOT_LIKE, operand);
	}

	public static Criterion notLikeIgnoreCase(String property, String operand) {
		return new Condition(property, Condition.Operator.NOT_LIKE_CI, operand);
	}

	public static Criterion between(String property, Object operand1, Object operand2) {
		return new Condition(property, Condition.Operator.BETWEEN, operand1, operand2);
	}

	public static Criterion notBetween(String property, Object operand1, Object operand2) {
		return new Condition(property, Condition.Operator.NOT_BETWEEN, operand1, operand2);
	}

	public static Criterion in(String property, Object... operands) {
		return new Condition(property, Condition.Operator.IN, operands);
	}

	public static Criterion notIn(String property, Object... operands) {
		return new Condition(property, Condition.Operator.NOT_IN, operands);
	}

	public static Criterion and(Criterion... criteria) {
		return new Junction(Junction.Logical.AND, criteria);
	}

	public static Criterion or(Criterion... criteria) {
		return new Junction(Junction.Logical.OR, criteria);
	}

	public static Criterion nothing() {
		return NOTHING;
	}

	public static abstract class FlattenPart {
		private final Type type;
		private final Object object;

		public FlattenPart(Type type, Object object) {
			this.type = type;
			this.object = object;
		}

		public Type getType() {
			return type;
		}

		public Object getObject() {
			return object;
		}

		public static enum Type {
			JUNCTION, CONDITION, IDENTIFIER
		}
	}
}
